package com.henghe.frame.auth.aop;

import com.henghe.frame.auth.entity.SysLog;
import com.henghe.frame.auth.service.CommOptLogAuthService;
import com.henghe.frame.auth.service.TokenUtil;
import com.henghe.frame.common.annotation.OptLog;
import com.henghe.frame.common.entity.Result;
import com.henghe.frame.common.util.PattenUtil;
import com.henghe.frame.common.util.StringUtils;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.lang.reflect.Method;
import java.nio.charset.StandardCharsets;
import java.util.Objects;

/**
 * Description:
 * Author: LiuWenQing
 * Datetime: 2023/4/4 15:20
 */
@Aspect
@Component
@Slf4j
public class LogDbAop {

    @Autowired
    private TokenUtil tokenUtil;
    @Autowired
    private CommOptLogAuthService commOptLogAuthService;

    @Pointcut("@annotation(com.henghe.frame.common.annotation.OptLog)")
    public void logPointCut() {
    }

    @AfterReturning(pointcut = "logPointCut()", returning = "jsonResult")
    public void doAfterReturning(JoinPoint joinPoint, Object jsonResult) {
        handleLog(joinPoint, null, jsonResult);
    }

    @AfterThrowing(value = "logPointCut()", throwing = "e")
    public void doAfterThrowing(JoinPoint joinPoint, Exception e) {
        handleLog(joinPoint, e, null);
    }

    protected void handleLog(final JoinPoint joinPoint, final Exception e, Object jsonResult) {
        try {
            ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
            HttpServletRequest request = attributes.getRequest();
            Method method = this.findMethodByName(joinPoint);
            Class<? extends Object> clazz = joinPoint.getTarget().getClass();
            Long userId = tokenUtil.getUserId();
            String userName = tokenUtil.getUserName();
            if (userId == null)
                return;
            if (Objects.nonNull(method)) {
                boolean hasAnnotation = method.isAnnotationPresent(OptLog.class);
                if (hasAnnotation) {
                    OptLog logInfo = method.getAnnotation(OptLog.class);
                    boolean valid = logInfo.valid();
                    if (!valid)
                        return;
                    String methodDesc = logInfo.value();
                    if (method.isAnnotationPresent(ApiOperation.class) && StringUtils.isNull(methodDesc))
                        methodDesc = method.getAnnotation(ApiOperation.class).value();

                    String logPosition = logInfo.logsPostion().toString();
                    // controller层的注解才扫描入库
                    if (OptLog.Position.Action.toString().equals(logPosition)) {
                        String logArgs = (String) request.getAttribute("logArgs");
                        String logDesc = null;
                        try {
                            if (StringUtils.isNotEmpty(logArgs))
                                logDesc = PattenUtil.handleLogDesc(logInfo.logDesc(), logArgs.split(","));
                        } catch (Exception exception1) {
                            return;
                        }
                        if (StringUtils.isNotEmpty(logDesc))
                            logDesc = "操作人: " + userName + " " + logInfo.logDesc();

                        StringBuilder data = new StringBuilder();
                        String line;
                        BufferedReader reader;
                        try {
                            reader = new BufferedReader(new InputStreamReader(request.getInputStream(), StandardCharsets.UTF_8));
                            while (null != (line = reader.readLine())) {
                                data.append(line);
                            }
                        } catch (IOException ex) {
                            ex.printStackTrace();
                            return;
                        }
                        Result result = null;
                        try {
                            result = (Result) jsonResult;
                        } catch (Exception e3) {
                            e3.printStackTrace();
                        } finally {
                            SysLog log = SysLog.builder()
                                    .optApi(method.getName() + "@" + clazz.getName())
                                    .optName(methodDesc)
                                    .optTypeId(logInfo.optTypeId())
                                    .requestMethod(request.getMethod())
                                    .paramsUrl(request.getServletPath())
                                    .queryString(request.getQueryString())
                                    .paramsBody(StringUtils.isNotEmpty(data) ? data.toString() : null)
                                    .logDesc(logDesc)
                                    .build();
                            if (result != null && result.getCode() != null && result.getCode() == 600) {
                                log.setOptResultType(1);
                            } else {
                                log.setOptResultType(2);
                            }
                            commOptLogAuthService.sysLogInsert(log);
                        }
                    }
                }
            }
        } catch (
                Exception exception) {
            log.error("日志aop出现异常,信息:{}", exception.getMessage());
            exception.printStackTrace();
        }

    }

    private Method findMethodByName(JoinPoint point) {
        String methodName = point.getSignature().getName();
        if (null != methodName && !"".equals(methodName)) {
            Method[] methods = point.getSignature().getDeclaringType().getMethods();
            Method[] var4 = methods;
            int var5 = methods.length;

            for (int var6 = 0; var6 < var5; ++var6) {
                Method method = var4[var6];
                if (method.getName().equals(methodName)) {
                    return method;
                }
            }
        }

        return null;
    }

//    private void setRequestValue(JoinPoint joinPoint, SysLog operLog) throws Exception {
//        String requestMethod = operLog.getRequestMethod();
//        if (HttpMethod.PUT.name().equals(requestMethod) || HttpMethod.POST.name().equals(requestMethod)) {
//            String params = argsArrayToString(joinPoint.getArgs());
//            operLog.setRequestParam(StringUtils.substring(params, 0, 2000));
//        } else {
//            Map<?, ?> paramsMap = (Map<?, ?>) ServletUtils.getRequest().getAttribute(HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE);
//            operLog.setRequestParam(StringUtils.substring(paramsMap.toString(), 0, 2000));
//        }
//    }

//    private String argsArrayToString(Object[] paramsArray) {
//        String params = "";
//        if (paramsArray != null && paramsArray.length > 0) {
//            for (int i = 0; i < paramsArray.length; i++) {
//                if (StringUtils.isNotNull(paramsArray[i]) && !isFilterObject(paramsArray[i])) {
//                    Object jsonObj = JSON.toJSON(paramsArray[i]);
//                    params += jsonObj.toString() + " ";
//                }
//            }
//        }
//        return params.trim();
//    }
//
//    public boolean isFilterObject(final Object o) {
//        Class<?> clazz = o.getClass();
//        if (clazz.isArray()) {
//            return clazz.getComponentType().isAssignableFrom(MultipartFile.class);
//        } else if (Collection.class.isAssignableFrom(clazz)) {
//            Collection collection = (Collection) o;
//            for (Iterator iter = collection.iterator(); iter.hasNext(); ) {
//                return iter.next() instanceof MultipartFile;
//            }
//        } else if (Map.class.isAssignableFrom(clazz)) {
//            Map map = (Map) o;
//            for (Iterator iter = map.entrySet().iterator(); iter.hasNext(); ) {
//                Map.Entry entry = (Map.Entry) iter.next();
//                return entry.getValue() instanceof MultipartFile;
//            }
//        }
//        return o instanceof MultipartFile || o instanceof HttpServletRequest || o instanceof HttpServletResponse
//                || o instanceof BindingResult;
//    }
}
